package service

import (
	"time"
	"todolist/model"
	"todolist/pkg/e"
	"todolist/pkg/utils"
	"todolist/serializer"
)

type (
	ShowTaskService   struct{}
	DeleteTaskService struct{}
	UpdateTaskService struct {
		ID      uint   `form:"id" json:"id"`
		Title   string `form:"title" json:"title" binding:"required,min=2,max=100"`
		Content string `form:"content" json:"content" binding:"max=1000"`
		Status  int    `form:"status" json:"status"`
	}

	CreateTaskService struct {
		Title   string `form:"title" json:"title" binding:"required,min=2,max=100"`
		Content string `form:"content" json:"content" binding:"max=1000"`
		Status  int    `form:"status" json:"status"`
	}

	SearchTaskService struct {
		Info string `from:"info" json:"info"`
	}

	ListTasksService struct {
		Limit int `form:"limit" json:"limit"`
		Start int `form:"start" json:"start"`
	}
)

func (service *CreateTaskService) Create(id uint) serializer.Response {
	var user model.User
	model.DB.First(&user, id)
	task := model.Task{
		User:      user,
		Title:     service.Title,
		Content:   service.Content,
		Status:    0,
		StartTime: time.Now().Unix(),
	}

	code := e.SUCCESS
	err := model.DB.Create(&task).Error
	if err != nil {
		utils.LogrusObj.Info(err)
		code = e.ErrorDatabase
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}

	return serializer.Response{
		Status: code,
		Data:   serializer.BuildTask(task),
		Msg:    e.GetMsg(code),
	}
}

func (service *ListTasksService) List(id uint) serializer.Response {
	var tasks []model.Task
	var total int64
	if service.Limit == 0 {
		// todo 15 means what ?
		service.Limit = 15
	}
	model.DB.Model(model.Task{}).Preload("User").
		Where("uid=?", id).Count(&total).
		Limit(service.Limit).Offset((service.Start - 1) * service.Limit).
		Find(&tasks)

	return serializer.BuildListResponse(serializer.BuildTasks(tasks), uint(total))
}

func (service *ShowTaskService) Show(id string, uid uint) serializer.Response {
	var task model.Task
	code := e.SUCCESS
	ctx := model.DB.Model(model.Task{}).Where("id=? AND uid=?", id, uid).First(&task)
	if ctx.RowsAffected == 0 {
		code = e.ErrorPriority
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	if err := ctx.Error; err != nil {
		utils.LogrusObj.Info(err)
		code = e.ErrorDatabase
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	task.AddView()
	return serializer.Response{
		Status: code,
		Data:   serializer.BuildTask(task),
		Msg:    e.GetMsg(code),
	}
}

func (service *DeleteTaskService) Delete(id string, uid uint) serializer.Response {
	var task model.Task
	code := e.SUCCESS
	err := model.DB.First(&task, id).Error

	if err != nil {
		utils.LogrusObj.Info(err)
		code = e.ErrorDatabase
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}

	ctx := model.DB.Where("uid= ?", uid).Delete(&task)
	if err = ctx.Error; err != nil {
		utils.LogrusObj.Info(err)
		code = e.ErrorDatabase
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}

	if ctx.RowsAffected == 0 {
		code = e.ErrorPriority
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
	}
}

func (service *UpdateTaskService) Update(id string, uid uint) serializer.Response {
	var task model.Task
	code := e.SUCCESS
	ctx := model.DB.Model(model.Task{}).Where("id=? AND uid=?", id, uid).First(&task)
	if ctx.RowsAffected == 0 {
		code = e.ErrorPriority
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	task.Content = service.Content
	task.Status = service.Status
	task.Title = service.Title

	err := model.DB.Save(&task).Error
	if err != nil {
		code = e.ErrorDatabase
		utils.LogrusObj.Info(err)
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}

	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
		Data:   "Updating Successfully!",
	}
}

func (service *SearchTaskService) Search(id uint) serializer.Response {
	code := e.SUCCESS
	var tasks []model.Task
	model.DB.Where("uid=?", id).Preload("User").First(&tasks)
	err := model.DB.Model(&model.Task{}).Where("title LIKE ? OR content LIKE ?",
		"%"+service.Info+"%", "%"+service.Info+"%").Find(&tasks).Error
	if err != nil {
		utils.LogrusObj.Info(err)
		code = e.ErrorDatabase
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}

	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
		Data:   serializer.BuildTasks(tasks),
	}
}
